package com.ssy.lingxi.order.serviceimpl.web;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.BasePurchaseProcessDO;
import com.ssy.lingxi.order.entity.OrderPurchaseProcessDO;
import com.ssy.lingxi.order.model.constant.BasePurchaseProcessEnum;
import com.ssy.lingxi.order.model.constant.OrderServiceContants;
import com.ssy.lingxi.order.model.vo.basic.request.OrderProcessIdVO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderProcessUpdateStatusVO;
import com.ssy.lingxi.order.model.vo.process.request.OrderProcessNamePageVO;
import com.ssy.lingxi.order.model.vo.process.request.OrderPurchaseProcessContractPageVO;
import com.ssy.lingxi.order.model.vo.process.request.OrderPurchaseProcessUpdateVO;
import com.ssy.lingxi.order.model.vo.process.request.OrderPurchaseProcessVO;
import com.ssy.lingxi.order.model.vo.process.response.BasePurchaseProcessVO;
import com.ssy.lingxi.order.model.vo.process.response.OrderProcessPageQueryVO;
import com.ssy.lingxi.order.model.vo.process.response.OrderPurchaseProcessContractQueryVO;
import com.ssy.lingxi.order.model.vo.process.response.OrderPurchaseProcessDetailVO;
import com.ssy.lingxi.order.repository.OrderPurchaseProcessRepository;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.base.IBaseOrderPurchaseProcessContractService;
import com.ssy.lingxi.order.service.base.IBasePurchaseProcessService;
import com.ssy.lingxi.order.service.platform.IPlatformPurchaseProcessService;
import com.ssy.lingxi.order.service.web.IOrderPurchaseProcessService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 采购流程规则配置相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-25
 */
@Service
public class OrderPurchaseProcessServiceImpl implements IOrderPurchaseProcessService {
    @Resource
    private IBaseCacheService baseCacheService;

    @Resource
    private IBasePurchaseProcessService basePurchaseProcessService;

    @Resource
    private IPlatformPurchaseProcessService platformPurchaseProcessService;

    @Resource
    private IBaseOrderPurchaseProcessContractService baseOrderPurchaseProcessContractService;

    @Resource
    private OrderPurchaseProcessRepository orderPurchaseProcessRepository;

    /**
     * 分页查询采购流程规则
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<OrderProcessPageQueryVO>> pagePurchaseProcesses(HttpHeaders headers, OrderProcessNamePageVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);

        Pageable pageable = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        Specification<OrderPurchaseProcessDO> specification = (Specification<OrderPurchaseProcessDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), loginUser.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), loginUser.getMemberRoleId()));

            if(StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<OrderPurchaseProcessDO> pageList = orderPurchaseProcessRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(process -> {
            OrderProcessPageQueryVO queryVO = new OrderProcessPageQueryVO();
            queryVO.setProcessId(process.getId());
            queryVO.setName(process.getName());
            queryVO.setProcessName(BasePurchaseProcessEnum.getNameByCode(process.getBasePurchaseProcess().getCode()));
            queryVO.setCreateTime(process.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            queryVO.setStatus(process.getStatus());
            queryVO.setStatusName(EnableDisableStatus.getNameByCode(process.getStatus()));
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 新增采购规则页面 - 查询基础采购流程列表
     *
     * @param headers Http头部信息
     * @return 查询结果
     */
    @Override
    public Wrapper<List<BasePurchaseProcessVO>> listBasePurchaseProcess(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        //从平台后台的配置中查询
        return Wrapper.success(platformPurchaseProcessService.findOrderPurchaseProcess(loginUser.getMemberId(), loginUser.getMemberRoleId()));
    }

    /**
     * 新增采购流程规则
     *
     * @param headers   HttpHeaders信息
     * @param processVO 接口参数
     * @return 新增结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> createPurchaseProcess(HttpHeaders headers, OrderPurchaseProcessVO processVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);

        //Step 1: 判断基础流程
        BasePurchaseProcessDO basePurchaseProcess = basePurchaseProcessService.findById(processVO.getBaseProcessId());
        if(basePurchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_BASE_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        //Step 2: 查询同类型的流程
        //Step 2-1: 判断是否已经存在相同的配置
        List<OrderPurchaseProcessDO> purchaseProcesses = orderPurchaseProcessRepository.findByMemberIdAndRoleIdAndProcessType(loginUser.getMemberId(), loginUser.getMemberRoleId(), basePurchaseProcess.getProcessType());
        if(purchaseProcesses.stream().anyMatch(process -> process.getBasePurchaseProcess().getId().equals(basePurchaseProcess.getId()))) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_EXISTS);
        }

        //Step 2-2: 校验合同信息
        Wrapper<Void> checkResult = baseOrderPurchaseProcessContractService.checkContracts(purchaseProcesses, processVO.getAllContracts(), processVO.getContracts());
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return checkResult;
        }

        //Step 3: 新增
        OrderPurchaseProcessDO purchaseProcess = new OrderPurchaseProcessDO();
        purchaseProcess.setCreateTime(LocalDateTime.now());
        purchaseProcess.setMemberId(loginUser.getMemberId());
        purchaseProcess.setRoleId(loginUser.getMemberRoleId());
        purchaseProcess.setName(processVO.getName());
        purchaseProcess.setBasePurchaseProcess(basePurchaseProcess);
        purchaseProcess.setProcessKey(basePurchaseProcess.getProcessKey());
        purchaseProcess.setProcessType(basePurchaseProcess.getProcessType());
        purchaseProcess.setProcessKind(basePurchaseProcess.getProcessKind());
        purchaseProcess.setAllContracts(processVO.getAllContracts());
        purchaseProcess.setStatus(EnableDisableStatus.ENABLE.getCode());
        //由于有 CascadeType.DETACH 的关联实体，所以要先保存一下
        orderPurchaseProcessRepository.saveAndFlush(purchaseProcess);

        // 3-1 : 新增合同信息
        baseOrderPurchaseProcessContractService.saveContracts(purchaseProcess, processVO.getAllContracts(), processVO.getContracts());
        // 3-2:  更新
        orderPurchaseProcessRepository.saveAndFlush(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 查询采购流程规则详情
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<OrderPurchaseProcessDetailVO> getPurchaseProcess(HttpHeaders headers, OrderProcessIdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        OrderPurchaseProcessDO purchaseProcess = orderPurchaseProcessRepository.findById(idVO.getProcessId()).orElse(null);
        if(purchaseProcess == null || !purchaseProcess.getMemberId().equals(loginUser.getMemberId())) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        OrderPurchaseProcessDetailVO detailVO = new OrderPurchaseProcessDetailVO();
        detailVO.setProcessId(purchaseProcess.getId());
        detailVO.setBaseProcessId(purchaseProcess.getBasePurchaseProcess().getId());
        detailVO.setProcessType(purchaseProcess.getProcessType());
        detailVO.setName(purchaseProcess.getName());
        detailVO.setAllContracts(purchaseProcess.getAllContracts());
        return Wrapper.success(detailVO);
    }

    /**
     * 分页查询采购流程规则适用合同列表
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<OrderPurchaseProcessContractQueryVO>> pagePurchaseProcessProducts(HttpHeaders headers, OrderPurchaseProcessContractPageVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        OrderPurchaseProcessDO purchaseProcess = orderPurchaseProcessRepository.findById(pageVO.getProcessId()).orElse(null);
        if(purchaseProcess == null || !purchaseProcess.getMemberId().equals(loginUser.getMemberId())) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        return baseOrderPurchaseProcessContractService.pageContracts(purchaseProcess, pageVO.getDigest(), pageVO.getCurrent(), pageVO.getPageSize());
    }

    /**
     * 修改采购流程规则
     *
     * @param headers  HttpHeaders信息
     * @param updateVO 接口参数
     * @return 修改结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updatePurchaseProcess(HttpHeaders headers, OrderPurchaseProcessUpdateVO updateVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        OrderPurchaseProcessDO purchaseProcess = orderPurchaseProcessRepository.findById(updateVO.getProcessId()).orElse(null);
        if(purchaseProcess == null || !purchaseProcess.getMemberId().equals(loginUser.getMemberId())) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        //Step 1: 判断基础流程
        BasePurchaseProcessDO basePurchaseProcess = basePurchaseProcessService.findById(updateVO.getBaseProcessId());
        if(basePurchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_BASE_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        //Step 2: 查询同类型的流程
        //Step 2-1: 判断是否已经存在相同的配置
        List<OrderPurchaseProcessDO> purchaseProcesses = orderPurchaseProcessRepository.findByMemberIdAndRoleIdAndProcessTypeAndIdNot(loginUser.getMemberId(), loginUser.getMemberRoleId(), basePurchaseProcess.getProcessType(), purchaseProcess.getId());
        if(purchaseProcesses.stream().anyMatch(process -> process.getBasePurchaseProcess().getId().equals(basePurchaseProcess.getId()))) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_EXISTS);
        }

        //Step 2-2: 校验合同信息
        Wrapper<Void> checkResult = baseOrderPurchaseProcessContractService.checkContracts(purchaseProcesses, updateVO.getAllContracts(), updateVO.getContracts());
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return checkResult;
        }

        //Step 3: 修改
        purchaseProcess.setCreateTime(LocalDateTime.now());
        purchaseProcess.setName(updateVO.getName());
        purchaseProcess.setBasePurchaseProcess(basePurchaseProcess);
        purchaseProcess.setProcessKey(basePurchaseProcess.getProcessKey());
        purchaseProcess.setProcessType(basePurchaseProcess.getProcessType());
        purchaseProcess.setProcessKind(basePurchaseProcess.getProcessKind());
        purchaseProcess.setAllContracts(updateVO.getAllContracts());

        // 3-1 : 修改合同信息
        baseOrderPurchaseProcessContractService.updateContracts(purchaseProcess, updateVO.getAllContracts(), updateVO.getContracts());
        // 保存
        orderPurchaseProcessRepository.saveAndFlush(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 修改采购流程规则状态
     *
     * @param headers  HttpHeaders信息
     * @param statusVO 接口参数
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> updatePurchaseProcessStatus(HttpHeaders headers, OrderProcessUpdateStatusVO statusVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        OrderPurchaseProcessDO purchaseProcess = orderPurchaseProcessRepository.findById(statusVO.getProcessId()).orElse(null);
        if(purchaseProcess == null || !purchaseProcess.getMemberId().equals(loginUser.getMemberId())) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        purchaseProcess.setStatus(statusVO.getStatus());
        orderPurchaseProcessRepository.saveAndFlush(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 删除采购流程规则
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 删除结果
     */
    @Override
    public Wrapper<Void> deletePurchaseProcess(HttpHeaders headers, OrderProcessIdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        OrderPurchaseProcessDO purchaseProcess = orderPurchaseProcessRepository.findById(idVO.getProcessId()).orElse(null);
        if(purchaseProcess == null || !purchaseProcess.getMemberId().equals(loginUser.getMemberId())) {
            return Wrapper.fail(ResponseCode.ORDER_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        orderPurchaseProcessRepository.delete(purchaseProcess);
        return Wrapper.success();
    }
}
